/*Yipeng Huang and Scott Rogowski*/
/*yh2315 smr2167*/

//Second stage in a mips pipeline
module DecodeStageWithRegisters(
					clk,reset,pause,
					register_write_md,
					instructions,
					bubble,
					register_write_address,register_write_data,
					enable_wait_for, set_wait_for, waiting_on_writeback,
					pc_plus_four_in,
					pc_plus_four,
					register_destination,ALU_source,mem_to_register,register_write,memory_read,memory_write,branch,jump,ALU_op,
					read_value_0,read_value_1,
					sign_extended,
					instruction_20_16, instruction_15_11,
					jump_address,
					bunch_debug
					);


	///////////////////////////////////////////////////////////
	////////////////////////*THE INPUTS*///////////////////////
	///////////////////////////////////////////////////////////
	
	input clk;
	input reset;
	input pause; //The pause is used for when the entire pipeline should stop.  It pauses the 'wall registers'
	
	//The principle input is the instructions from the fetch stage.
	input [31:0] instructions;
	input bubble; //One bit input that triggers a bubble in the pipeline

	//What to give to the registers.	
	input [4:0] register_write_address;
	input [31:0] register_write_data;
	
	//An enabler and index pair that tells the register to wait
	input enable_wait_for;
	input [4:0] set_wait_for;
	
	//This is the pass through program increment
	input [31:0] pc_plus_four_in;
	
	//The only control line affecting the decode operation.  This is passed back from the memory stage
	input register_write_md;
	
	/////////////////////////////////////////////////////////////////////////
	/*THE OUTPUTS, every output has a corresponding pre-delay-register wire*/
	/////////////////////////////////////////////////////////////////////////
	
	//The pass through program increment
	output [31:0] pc_plus_four;
	
	//The control wires.  This is a complete list and all will be generated by the controller
	wire register_destination_mid;	output register_destination;
	wire ALU_source_mid;			output ALU_source;
	wire mem_to_register_mid;		output mem_to_register;
	wire register_write_mid;		output register_write;
	wire memory_read_mid;			output memory_read;
	wire memory_write_mid;			output memory_write;
	wire branch_mid;				output branch;
	wire jump_mid;					output jump;
	wire [1:0] ALU_op_mid;			output [1:0] ALU_op;

	//The wires from the register.
	wire [31:0] read_value_0_mid;	output [31:0] read_value_0;
	wire [31:0] read_value_1_mid;	output [31:0] read_value_1;
	
	//Output that says which registers are currently not accessible
	output [31:0] waiting_on_writeback;
	
	//Wires that carry logical 1 to force register to be enabled
	wire one;
	assign one = 1'b1;

	//Sign extended for I-type and J-type instructions
	wire [31:0] sign_extended_mid;
	output [31:0] sign_extended;
	
	//The remaining registers for R-type instructions
	output [4:0] instruction_20_16;
	output [4:0] instruction_15_11;
	
	//Wires for carrying jump address
	wire [25:0] instructions_25_0;
	wire [27:0] instructions_shifted_left_two;
	wire [31:28] pc_plus_four_31_28;
	wire [31:0] jump_address_mid;	output [31:0] jump_address;
	
	//output for debugging the control unit
	output [9:0] bunch_debug;

	//////////////////////////////////////////////////////
	//////////////////*WIRE THE MODULES*//////////////////
	//////////////////////////////////////////////////////
	
	//BUBBLE LOGIC
	//Logic for creating an opcode that is 111111 bubble should be created
	wire [5:0] instructions_with_bubble;
/*	assign instructions_with_bubble = instructions[31:26] | {6{bubble}};	
*/	assign instructions_with_bubble = instructions[31:26];	

	//The controller which takes raw mips assembly and translates it to the necessary control wires
	Control control (	
				.opcode(instructions_with_bubble), //opcode is 111111 when bubble created
				.register_destination(register_destination_mid),
				.ALU_source(ALU_source_mid),
				.mem_to_register(mem_to_register_mid),
				.register_write(register_write_mid),
				.memory_read(memory_read_mid),
				.memory_write(memory_write_mid),
				.branch(branch_mid),
				.jump(jump_mid),
				.ALU_op(ALU_op_mid),
				.bunch_debug(bunch_debug)
				);
	
	
	
	//The registers can read up to two registers at once and write one register.
	wire throwaway0; //for now, we don't need the read_valids.
	wire throwaway1; //for now, we don't need the read_valids.
	RegisterMemory registerMemory (
				.read_0_enable(one),
				.read_0_index(instructions[25:21]),
				.read_0_valid(throwaway0),
				.read_0_value(read_value_0_mid),
				.read_1_enable(one),
				.read_1_index(instructions[20:16]),
				.read_1_valid(throwaway1),
				.read_1_value(read_value_1_mid),
				.write_enable(register_write_md),
				.write_index(register_write_address),
				.write_data(register_write_data),
				.enable_wait_for(enable_wait_for),
				.set_wait_for(set_wait_for),
				.waiting_on_writeback(waiting_on_writeback),
				.reset(reset),
				.clk(clk)
				);
	
	//Extend the sign
	SignExtender s (.sign_in(instructions[15:0]),.sign_out(sign_extended_mid));
	
	//////////////////////////////////////////////////////////
	/////////////////////*JUMP LOGIC*/////////////////////////
	//////////////////////////////////////////////////////////
	
	assign instructions_25_0 = instructions[25:0];
	assign instructions_shifted_left_two = { instructions_25_0 , {2{1'b0}} };
	assign pc_plus_four_31_28 = pc_plus_four_in[31:28];
	assign jump_address_mid = {pc_plus_four_31_28, instructions_shifted_left_two};
	
	
	
	//////////////////////////////////////////////////////////
	////////////////*DELAY REGISTERS*/////////////////////////
	//////////////////////////////////////////////////////////
	
	//Control lines
	FF f0 (.clk(clk), .reset(reset), .enable(!pause), .set(register_destination_mid), .q(register_destination));
	FF f1 (.clk(clk), .reset(reset), .enable(!pause), .set(ALU_source_mid), .q(ALU_source));
	FF f2 (.clk(clk), .reset(reset), .enable(!pause), .set(mem_to_register_mid), .q(mem_to_register));
	FF f3 (.clk(clk), .reset(reset), .enable(!pause), .set(register_write_mid), .q(register_write));
	FF f4 (.clk(clk), .reset(reset), .enable(!pause), .set(memory_read_mid), .q(memory_read));
	FF f5 (.clk(clk), .reset(reset), .enable(!pause), .set(memory_write_mid), .q(memory_write));
	FF f6 (.clk(clk), .reset(reset), .enable(!pause), .set(branch_mid), .q(branch));
	FF f7 (.clk(clk), .reset(reset), .enable(!pause), .set(jump_mid), .q(jump));
	DelayRegisterFile #(2) 	f8 (.clk(clk), .reset(reset), .pause(pause), .data(ALU_op_mid), .q(ALU_op));

	//Incremented program clock
	DelayRegisterFile #(32) d0 (.clk(clk), .reset(reset), .pause(pause), .data(pc_plus_four_in), .q(pc_plus_four));
	
	//Register reads
	DelayRegisterFile #(32) d1 (.clk(clk), .reset(reset), .pause(pause), .data(read_value_0_mid), .q(read_value_0));
	DelayRegisterFile #(32) d2 (.clk(clk), .reset(reset), .pause(pause), .data(read_value_1_mid), .q(read_value_1));
	
	//Sign extended
	DelayRegisterFile #(32) d3 (.clk(clk), .reset(reset), .pause(pause), .data(sign_extended_mid), .q(sign_extended));
	
	//Jump address
	DelayRegisterFile #(32) d6 (.clk(clk), .reset(reset), .pause(pause), .data(jump_address_mid), .q(jump_address));

	//Pass through instructions
	DelayRegisterFile #(5) d4 (.clk(clk), .reset(reset), .pause(pause), .data(instructions[20:16]), .q(instruction_20_16));
	DelayRegisterFile #(5) d5 (.clk(clk), .reset(reset), .pause(pause), .data(instructions[15:11]), .q(instruction_15_11));

	endmodule